package com.sanri.tools.modules.mock.l7.http.service.interceptors;

import com.sanri.tools.modules.core.exception.ToolException;
import com.sanri.tools.modules.mock.l7.http.service.dtos.ResponseConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.omg.PortableInterceptor.Interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 响应拦截器
 */
public interface ResponseInterceptor {

    /**
     * 当前拦截器是否匹配请求
     * @param request
     * @return
     */
    boolean match(HttpServletRequest request);

    /**
     * 拦截请求
     * @param chain
     * @return
     */
    void interceptor(ResponseConfig responseConfig, IntermediateData intermediateData, Chain chain) ;

    @Slf4j
    public abstract class Chain{
        protected List<ResponseInterceptor> interceptors = new LinkedList<>();

        /**
         * 当前执行拦截器的位置索引
         */
        protected int index;

        public void addInterceptorLast(ResponseInterceptor responseInterceptor){
            interceptors.add(responseInterceptor);
        }

        public void addInterceptorAfter(ResponseInterceptor responseInterceptor,Class<? extends ResponseInterceptor> clazz){
            for (int i = 0; i < interceptors.size(); i++) {
                final ResponseInterceptor responseInterceptorPart = interceptors.get(i);
                if (responseInterceptorPart.getClass() == clazz){
                    interceptors.add(i - 1, responseInterceptor);
                    return;
                }
            }
            throw new ToolException("未找到指定拦截器:"+clazz);
        }

        /**
         * 处理请求
         * @param request
         * @return
         */
        public void interceptor(ResponseConfig responseConfig, IntermediateData intermediateData) {
            if (CollectionUtils.isEmpty(interceptors)){
                log.error("没有指定拦截器列表, 拦截器链执行失败");
                return ;
            }

            if (index >= interceptors.size()){
                log.info("所有拦截器执行完毕, 没有下一个拦截器了");
                return ;
            }
            // 从第一个开始顺序执行; 由子拦截器决定是否要调用下一个还是要跳着调
            final ResponseInterceptor responseInterceptor = interceptors.get(index ++);
            responseInterceptor.interceptor(responseConfig, intermediateData, this);
        }

        /**
         * 获取拦截器列表
         * @return
         */
        public List<ResponseInterceptor> getInterceptors() {
            return interceptors;
        }

        /**
         * 跳过下一个
         * @return
         */
        public boolean skipNext(){
            if (index >= interceptors.size() - 1){
                log.warn("跳过拦截器失败, 因为当前是最后一个拦截器了");
                return false;
            }
            index ++;
            return true;
        }

        /**
         * 从上一个拦截器重新执行, 当前
         * @return
         */
        public boolean repeatPreInterce(){
            if (index <= 0){
                log.warn("当前已经是第一个拦截器, 不可以跳到上一个");
                return false;
            }
            index --;
            return true;
        }

        public boolean skipTo(int index){
            if (index < 0 || index > interceptors.size()){
                log.warn("跳转的拦截器索引位置不正确, 当前拦截器数量为: {}", interceptors.size());
                return false;
            }
            this.index = index;
            return true;
        }

        /**
         * 跳转到指定拦截器
         * @param clazz
         * @return
         */
        public boolean skipTo(Class<? extends ResponseInterceptor> clazz){
            for (int i = 0; i < interceptors.size(); i++) {
                if (interceptors.get(i).getClass() == clazz){
                    index = i;
                    return true;
                }
            }
            return false;
        }

    }

}
